package com.hs.hlw.credit.system.web.components;

import com.hualongdata.aes.HLBizMsgCrypt;
import com.hs.hlw.credit.system.common.CsConstants;
import com.hs.hlw.credit.system.common.WebUtils;
import com.hs.hlw.credit.system.common.domain.AuthToken;
import com.hs.hlw.credit.system.common.setting.SessionSetting;
import com.hualongdata.exception.HlUnauthorizedException;
import com.hualongdata.util.TimeUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * Created by yangbajing(yangbajing@gmail.com) on 2016-09-08.
 */
@Component
public class CcTokenComponent {
    private static Logger logger = LoggerFactory.getLogger(CcTokenComponent.class);

    private final SessionSetting sessionSetting;
    private final HLBizMsgCrypt hlBizMsgCrypt;
    private final WebUtils webUtils;

    @Autowired
    public CcTokenComponent(SessionSetting sessionSetting, WebUtils webUtils) {
        this.sessionSetting = sessionSetting;
        this.webUtils = webUtils;
        this.hlBizMsgCrypt = new HLBizMsgCrypt(sessionSetting.getToken(), sessionSetting.getEncodingAesKey(), sessionSetting.getAppid());
    }

    public Cookie discardCookieFromToken() {
        Cookie cookie = webUtils.createCookie(CsConstants.CC_OWNER_TOKEN, "");
        cookie.setMaxAge(0);
        return cookie;
    }

    public Cookie discardSsoCookieFromToken(HttpServletRequest request) {
        Cookie cookie = webUtils.createCookie(request.getServerName(), CsConstants.SSO_COOKIE, "");
        cookie.setMaxAge(0);
        return cookie;
    }

    public Cookie createCookieFromToken(AuthToken token) {
        String str = token.toString();
        String encryptStr = hlBizMsgCrypt.encrypt(hlBizMsgCrypt.getRandomStr(), str);
        encryptStr = Base64.encodeBase64URLSafeString(encryptStr.getBytes());
        return createCookieFromString(encryptStr);
    }

    private Cookie createCookieFromString(String encryptTokenString) {
        return webUtils.createCookie(CsConstants.CC_OWNER_TOKEN, encryptTokenString);
    }

    private Cookie createCookieFromString(String domain, String tokenName, String encryptTokenString) {
        return webUtils.createCookie(domain, tokenName, encryptTokenString);
    }

    public Optional<AuthToken> getAuthTokenFromHttpRequest(HttpServletRequest request) {
        return getCookieValue(request, CsConstants.CC_OWNER_TOKEN)
                .filter(StringUtils::isNoneBlank)
                .map(value -> {
                    String str = new String(Base64.decodeBase64(value));
                    String decryptMsg = hlBizMsgCrypt.decrypt(str);
                    return AuthToken.fromString(decryptMsg);
                })
                .filter(this::isValidToken);
    }

    private Optional<String> getCookieValue(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null)
            return Optional.empty();
        return Stream.of(cookies)
                .filter(cookie -> name.equals(cookie.getName()))
                .findFirst()
                .map(Cookie::getValue);
    }

    public boolean isValidToken(AuthToken token) {
        long dueSeconds = token.timestamp + sessionSetting.getTimeout();
        long nowSeconds = TimeUtils.nowSeconds();
        return nowSeconds <= dueSeconds;
    }

    public void validationToken(AuthToken token) {
        if (!isValidToken(token)) {
            logger.debug("校验会话token超期");
            throw new HlUnauthorizedException();
        }
    }

    public void storeAuthTokenToHttpResponse(HttpServletResponse response, AuthToken authToken) {
        Cookie cookie = createCookieFromToken(authToken);
        response.addCookie(cookie);
        response.addHeader(CsConstants.CC_OWNER_TOKEN, cookie.getValue());
    }

    /**
     * 根据名字获取cookie
     *
     * @param request
     * @param name    cookie名字
     * @return
     */
    public Cookie getCookieByName(HttpServletRequest request, String name) {
        Cookie[] arr = request.getCookies();
        if (arr == null) {
            return null;
        }
        return Arrays.stream(arr).filter(cookie -> cookie.getName().equals(name)).findFirst().orElse(null);
    }

    public void store4ATokenToHttpResponse(HttpServletRequest request, HttpServletResponse response, String sessionCode) {
        String domain = request.getServerName();
        Cookie cookie = createCookieFromString(domain, CsConstants.SSO_COOKIE, sessionCode);
        response.addCookie(cookie);
    }
}
